﻿using System;
using System.ServiceModel;
using System.Timers;
using Microsoft.ServiceBus;

namespace SimpleServiceBus.Endpoints.DotNetServiceBus.Utilities
{
    public class AzureQueueManager : IDisposable
    {
        readonly QueueClient _queueClient;
        readonly Timer _queueRenewalTimer;
        private readonly TimeSpan _renewalBuffer = TimeSpan.FromMinutes(10);
        private readonly TimeSpan _timeToLive;

        public AzureQueueManager(Uri queueUri,string busUserName,string busPassword) : this(queueUri, busUserName, busPassword, TimeSpan.FromDays(1))
        {
        }

        public AzureQueueManager(Uri queueUri,string busUserName,string busPassword,TimeSpan timeToLive)
        {
            _timeToLive = timeToLive;
            
            _queueClient = GetOrCreateQueue(CreateUsernamePasswordCredential(busUserName,busPassword),queueUri,_timeToLive);
            
            _queueRenewalTimer = new Timer(_renewalBuffer.TotalMilliseconds);
            _queueRenewalTimer.Elapsed += TimerElapsedCallback;
            _queueRenewalTimer.AutoReset = false;
            _queueRenewalTimer.Start();
        }

        public QueueClient Queue { get { return _queueClient;}}

        public static TransportClientEndpointBehavior CreateUsernamePasswordCredential(string userName, string password)
        {
            var userNamePasswordServiceBusCredential = new TransportClientEndpointBehavior
                                                           {
                                                               CredentialType =
                                                                   TransportClientCredentialType
                                                                   .UserNamePassword
                                                           };
            userNamePasswordServiceBusCredential.Credentials.UserName.UserName = userName;
            userNamePasswordServiceBusCredential.Credentials.UserName.Password = password;
            return userNamePasswordServiceBusCredential;
        }

        private void TimerElapsedCallback(object source, ElapsedEventArgs e)
        {
            _queueClient.Renew(_timeToLive);
            _queueRenewalTimer.Interval = GetRenewalDelay().TotalMilliseconds;
            _queueRenewalTimer.Start();
        }

        private TimeSpan GetRenewalDelay()
        {
            return (_queueClient.GetPolicy().ExpirationInstant - DateTime.UtcNow).Subtract(_renewalBuffer);
        }

        public void Dispose()
        {
            _queueRenewalTimer.Stop();
        }

        public static QueueClient GetOrCreateQueue(TransportClientEndpointBehavior credentialBehavior, Uri queueUri,TimeSpan timeToLive)
        {
            QueueClient queueClient;
            try
            {
                queueClient = QueueManagementClient.GetQueue(credentialBehavior, queueUri);
                if (queueClient != null)
                {
                    if (queueClient.GetPolicy().ExpirationInstant <= DateTime.UtcNow)
                        queueClient.Renew((timeToLive));
                    return queueClient;
                }
            }
            catch (EndpointNotFoundException)
            {
                // Not found; absorb and make a new queue below. 
                // Other exceptions get bubbled up.
            }

            var queuePolicy = new QueuePolicy
                                  {
                                      ExpirationInstant = DateTime.UtcNow + timeToLive
                                  };
            queueClient = QueueManagementClient.CreateQueue(credentialBehavior, queueUri, queuePolicy);
            return queueClient;
            //_queuePolicy = _queueClient.GetPolicy();
        }
    }
}